/**
 * 
 */
package truerefactor.graph;

/**
 * Edge - Represents a connection between two nodes in the graph. It also
 * facilitates information relevant to UML classdiagrams, such as cardinality or
 * edge lables.
 * 
 * @author Isaac Griffith
 */
public class Edge {

    /**
     * source side of the edge
     */
    private CodeNode source;
    /**
     * destination side of the edge
     */
    private CodeNode destination;
    /**
     * flag for directionality of the edge
     */
    private boolean isDirected;
    /**
     * label for the source side
     */
    private String sourceLabel;
    /**
     * label for the destination side
     */
    private String destLabel;
    /**
     * Type of edge
     */
    private EdgeType type;
    /**
     * source side cardinality
     */
    private Cardinality sourceCard;
    /**
     * destination side cardinality
     */
    private Cardinality destCard;

    /**
     * Creates a new instance of an edge
     * 
     * @param source
     *            edge source node
     * @param destination
     *            edge destination node
     * @param type
     *            type of edge
     */
    public Edge(CodeNode source, CodeNode destination, EdgeType type)
    {
        this(source, destination, new Cardinality(), new Cardinality(), type, true);
    }

    /**
     * Creates a new instance of an edge
     * 
     * @param source
     *            source node
     * @param destination
     *            destination node
     * @param srcCard
     *            source cardinality
     * @param destCard
     *            destination cardinality
     * @param type
     *            edge type
     */
    public Edge(CodeNode source, CodeNode destination, Cardinality srcCard, Cardinality destCard, EdgeType type)
    {
        this(source, destination, srcCard, destCard, type, true);
    }

    /**
     * Create a new instance of an Edge
     * 
     * @param source
     *            source node
     * @param destination
     *            destination node
     * @param sourceCard
     *            source cardinality
     * @param destCard
     *            destination cardinality
     * @param type
     *            edge type
     * @param isDirected
     *            directed flag
     */
    public Edge(CodeNode source, CodeNode destination, Cardinality sourceCard, Cardinality destCard, EdgeType type,
            boolean isDirected)
    {
        this.source = source;
        this.destination = destination;
        this.destCard = destCard;
        this.sourceCard = sourceCard;
        this.type = type;
        this.sourceLabel = source.getIdentifier();
        this.destLabel = destination.getIdentifier();
        this.isDirected = isDirected;
    }

    /**
     * Creates a new instance of an Edge
     * 
     * @param source
     *            source node
     * @param destination
     *            destination node
     * @param type
     *            edge type
     * @param isDirected
     *            directed flag
     */
    public Edge(CodeNode source, CodeNode destination, EdgeType type, boolean isDirected)
    {
        this(source, destination, new Cardinality(), new Cardinality(), type, isDirected);
    }

    /**
     * @return the source node
     */
    public CodeNode getSource()
    {
        return source;
    }

    /**
     * sets the source node to the one provided
     * 
     * @param source
     *            the new source node
     */
    public void setSource(CodeNode source)
    {
        this.source = source;
    }

    /**
     * @return the destination node
     */
    public CodeNode getDestination()
    {
        return destination;
    }

    /**
     * sets the destination node to the one provided
     * 
     * @param destination
     *            the new destination node
     */
    public void setDestination(CodeNode destination)
    {
        this.destination = destination;
    }

    /**
     * @return true if this edge is directed, false otherwise
     */
    public boolean isDirected()
    {
        return isDirected;
    }

    /**
     * Sets whether this is a directed edge or not
     * 
     * @param isDirected
     *            the directed flag
     */
    public void setDirected(boolean isDirected)
    {
        this.isDirected = isDirected;
    }

    /**
     * @return the source label
     */
    public String getSourceLabel()
    {
        return sourceLabel;
    }

    /**
     * Sets the source label to the string provided
     * 
     * @param sourceLabel
     *            the new source Label
     */
    public void setSourceLabel(String sourceLabel)
    {
        this.sourceLabel = sourceLabel;
    }

    /**
     * @return the destination side label
     */
    public String getDestLabel()
    {
        return destLabel;
    }

    /**
     * Sets the destination label to the string provided
     * 
     * @param destLabel
     *            the new destination label
     */
    public void setDestLabel(String destLabel)
    {
        this.destLabel = destLabel;
    }

    /**
     * @return the edge type
     */
    public EdgeType getType()
    {
        return type;
    }

    /**
     * Sets the edge type to the EdgeType provided
     * 
     * @param type
     *            the new edge type
     */
    public void setType(EdgeType type)
    {
        this.type = type;
    }

    /**
     * @return the source cardinality
     */
    public Cardinality getSourceCard()
    {
        return sourceCard;
    }

    /**
     * Sets the source cardinality to the provided Cardinality
     * @param sourceCard
     *            the new source Cardinality
     */
    public void setSourceCardinality(Cardinality sourceCard)
    {
        this.sourceCard = sourceCard;
    }

    /**
     * @return the destination cardinality
     */
    public Cardinality getDestCard()
    {
        return destCard;
    }

    /**
     * Sets the destination cardinality to the Cardinality provided
     * @param destCard
     *            the new destination cardinality
     */
    public void setDestCardinality(Cardinality destCard)
    {
        this.destCard = destCard;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((destCard == null) ? 0 : destCard.hashCode());
        result = prime * result + ((destLabel == null) ? 0 : destLabel.hashCode());
        result = prime * result + ((destination == null) ? 0 : destination.hashCode());
        result = prime * result + (isDirected ? 1231 : 1237);
        result = prime * result + ((source == null) ? 0 : source.hashCode());
        result = prime * result + ((sourceCard == null) ? 0 : sourceCard.hashCode());
        result = prime * result + ((sourceLabel == null) ? 0 : sourceLabel.hashCode());
        result = prime * result + ((type == null) ? 0 : type.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
            return false;
        }
        if (!(obj instanceof Edge))
        {
            return false;
        }
        Edge other = (Edge) obj;
        if (destCard == null)
        {
            if (other.destCard != null)
            {
                return false;
            }
        }
        else if (!destCard.equals(other.destCard))
        {
            return false;
        }
        if (destLabel == null)
        {
            if (other.destLabel != null)
            {
                return false;
            }
        }
        else if (!destLabel.equals(other.destLabel))
        {
            return false;
        }
        if (destination == null)
        {
            if (other.destination != null)
            {
                return false;
            }
        }
        else if (!destination.equals(other.destination))
        {
            return false;
        }
        if (isDirected != other.isDirected)
        {
            return false;
        }
        if (source == null)
        {
            if (other.source != null)
            {
                return false;
            }
        }
        else if (!source.equals(other.source))
        {
            return false;
        }
        if (sourceCard == null)
        {
            if (other.sourceCard != null)
            {
                return false;
            }
        }
        else if (!sourceCard.equals(other.sourceCard))
        {
            return false;
        }
        if (sourceLabel == null)
        {
            if (other.sourceLabel != null)
            {
                return false;
            }
        }
        else if (!sourceLabel.equals(other.sourceLabel))
        {
            return false;
        }
        if (type != other.type)
        {
            return false;
        }
        return true;
    }
}
